package JAVA并发;

import java.util.concurrent.*;

/**
 * @author zhangmin
 * @create 2022-03-15 20:22
 *
 * J.U.C - AQS
 * java.util.concurrent（J.U.C）大大提高了并发性能，AQS 被认为是 J.U.C 的核心。
 * 1、CountDownLatch：用来控制一个或者多个线程等待多个线程。
 *                   维护了一个计数器 cnt，每次调用 countDown() 方法会让计数器的值减 1，减到 0 的时候，那些因为调用 await() 方法而在等待的线程就会被唤醒。
 * 2、CyclicBarrier：用来控制多个线程互相等待，只有当多个线程都到达时，<这些>线程才会继续执行。
 *                  和 CountdownLatch 相似，都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1，并进行等待，直到计数器为 0，
 *                  所有调用 await() 方法而在等待的线程才能继续执行。CyclicBarrier 和 CountdownLatch 的一个区别是，
 *                  CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用，所以它才叫做循环屏障。
 * 3、Semaphore：Semaphore 类似于操作系统中的信号量，可以控制对互斥资源的访问线程数。
 */
public class JUC_AQS7 {
    public static void main(String[] args) throws InterruptedException {
        final int totalThread=10;
        ExecutorService executorService= Executors.newCachedThreadPool();

        /*CountDownLatch countDownLatch=new CountDownLatch(totalThread);
        for (int i = 0; i < totalThread; i++) {
            executorService.execute(()->{
                System.out.println("run..");
                //每次将计数器-1，直到计数器为0，唤醒await的线程
                countDownLatch.countDown();
            });
        }
        //用countDownLatch等待多个线程都到达
        countDownLatch.await();
        System.out.println("end");*/

        /*CyclicBarrier cyclicBarrier=new CyclicBarrier(totalThread);
        for (int i = 0; i < totalThread; i++) {
            executorService.execute(()->{
                System.out.println("before...");
                try {
                    //将每个线程都等待，每次等待使得计数器-1，直到计数器为0，表示所有线程都到达，则将这些线程继续执行
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("after...");
            });
        }*/

        //每次只能有 3 个客户端同时访问，请求总数为 10
        final int clientCount=3;
        final int totalReq=10;
        Semaphore semaphore=new Semaphore(clientCount);
        for (int i = 0; i < totalReq; i++) {
            executorService.execute(()->{
                try {
                    //获取3个信号量中的一个
                    semaphore.acquire();
                    System.out.println(semaphore.availablePermits()+" ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //确保信号量释放
                    semaphore.release();
                }
            });
        }
        executorService.shutdown();
    }
}
